package com.zzyl.nursing.service.impl;

import java.util.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ServiceCapability;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductResponse;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.DevicePropertyStatusDto;
import com.zzyl.nursing.dto.UserDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.*;
import com.zzyl.nursing.service.WechatService;
import com.zzyl.nursing.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 老人家属Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-04-26
 */
@Slf4j
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper,FamilyMember> implements IFamilyMemberService
{
    @Autowired
    private FamilyMemberMapper familyMemberMapper;

    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );
    @Autowired
    private IoTDAClient ioTDAClient;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 查询老人家属
     * 
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     * 
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember)
    {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember)
    {
        return save(familyMember)?1:0;
    }

    /**
     * 修改老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember)
    {
        return updateById(familyMember)?1:0;
    }

    /**
     * 批量删除老人家属
     * 
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids))?1:0;
    }

    /**
     * 删除老人家属信息
     * 
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id)
    {
        return removeById(id)?1:0;
    }

    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenService tokenService;

    /**
     * 小程序端登录
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginRequestDto dto) {

        //获取openid  微信接口获取
        String openid = wechatService.getOpenid(dto.getCode());

        //根据openid查询用户信息
        FamilyMember familyMember = getOne(Wrappers.<FamilyMember>lambdaQuery().eq(FamilyMember::getOpenId, openid));

        //如果用户为空，构建用户，赋值一个openid
        if(ObjectUtil.isEmpty(familyMember)){
            familyMember = FamilyMember
                    .builder()
                    .openId(openid)
                    .build();
        }

        //获取用户的手机号  微信接口获取
        String phone = wechatService.getPhone(dto.getPhoneCode());

        //保存或更新用户
        insertOrUpdateFamilyMember(familyMember,phone);

        //生成token返回
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", familyMember.getId());
        claims.put("userName", familyMember.getName());

        String token = tokenService.createToken(claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setNickName(familyMember.getName());
        loginVo.setToken(token);

        return loginVo;
    }

    /**
     * 保存或更新用户
     * @param familyMember
     * @param phone
     */
    private void insertOrUpdateFamilyMember(FamilyMember familyMember, String phone) {

        //判断手机号与数据库的手机号是否一致
        if(ObjectUtil.notEqual(familyMember.getPhone(),phone)){
            familyMember.setPhone(phone);
        }
        //判断是否存在id，如果存在id，则更新，不存在则保存
        if(ObjectUtil.isNotEmpty(familyMember.getId())){
            updateById(familyMember);
            return;
        }
        //获取用户的昵称
        int index = (int)(Math.random() * DEFAULT_NICKNAME_PREFIX.size());
        String nickName = DEFAULT_NICKNAME_PREFIX.get(index) + StringUtils.substring(phone,7,11);
        familyMember.setName(nickName);
        //保存
        save(familyMember);

    }


    /**
     * 绑定家人
     */
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private FamilyMemberElderMapper familyMemberElderMapper;

    @Autowired
    private ElderMapper elderMapper;
    @Override
    public void add(UserDto userDto) {
        // 1.判断是否登录小程序
        // 获取用户信息
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("请先登录小程序");
        }

        // 2.小程序端输入信息绑定
        // 3.查看信息是否为空
        if (ObjectUtil.isEmpty(userDto)) {
            throw new BaseException("绑定内容不能为空");
        }

        // 4.身份验证，家人姓名和身份证号必须是养老院入住的老人
        Elder elder = elderMapper.selectOne(new LambdaQueryWrapper<Elder>()
                .eq(Elder::getIdCardNo, userDto.getIdCard())
                .eq(Elder::getName, userDto.getName())
                .eq(Elder::getStatus, 1)
        );
        if (ObjectUtil.isEmpty(elder)) {
            throw new BaseException("老人不存在");
        }

        // 5.判断是否签订合同
        // 根据老人id查询合同信息
        Contract contract = contractMapper.selectOne(new LambdaQueryWrapper<Contract>()
                .eq(Contract::getElderId, elder.getId())
                .eq(Contract::getStatus, 1)
        );
        if (ObjectUtil.isEmpty(contract)) {
            throw new BaseException("未查询到合同信息，老人不存在");
        }

        // 6.判断是否绑定过此家人
        Long count = familyMemberElderMapper.selectCount(
                new LambdaQueryWrapper<FamilyMemberElder>().eq(FamilyMemberElder::getFamilyMemberId, userId)
                        .eq(FamilyMemberElder::getElderId, elder.getId()));
        if (count > 0) {
            throw new BaseException("此家人已绑定过此老人");
        }

        // 7.绑定成功，保存信息
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();
        familyMemberElder.setRemark(userDto.getRemark());
        familyMemberElder.setElderId(elder.getId());
        familyMemberElder.setFamilyMemberId(userId);
        familyMemberElderMapper.insert(familyMemberElder);
    }


    /**
     * 1.2 查询家人列表
     *  简单 (sql语句查询)
     * @return
     */
    @Override
    public List<UserVo> my() {
        // 1.获取当前登录用户id
        Long userId = UserThreadLocal.getUserId();
        return familyMemberElderMapper.getUserVoList(userId);
    }


    /**
     * 1.2 查询家人列表
     *  复杂  (Mp查询)
     */
/*    @Override
    public List<UserVo> my() {
        // 1.获取当前登录用户id
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("用户未登录");
        }

        // 2.根据用户id查询家人信息
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(
                new LambdaQueryWrapper<FamilyMemberElder>().eq(FamilyMemberElder::getFamilyMemberId, userId));

        List<UserVo> userVos = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(familyMemberElders)) {
            // 收集所有老人ID
            List<Long> elderIds = familyMemberElders.stream()
                    .map(FamilyMemberElder::getElderId)
                    .collect(Collectors.toList());

            // 批量查询老人信息并构建Map
            Map<Long, String> elderMap = elderMapper.selectBatchIds(elderIds)
                    .stream()
                    .collect(Collectors.toMap(Elder::getId, Elder::getName));

            // 转换为UserVo
            familyMemberElders.forEach(fme -> {
                UserVo userVo = BeanUtil.copyProperties(fme, UserVo.class);
                String name = elderMap.get(fme.getElderId());
                if (name != null) {
                    userVo.setElderName(name);
                }
                userVos.add(userVo);
            });
        }
        // 3.返回
        return userVos;
    }*/


    /**
     * 获取家人列表  - 分页
     *sql查询
     * @return
     */
   /* @Override
    public List<MemberVo> listByPage2() {
        return familyMemberElderMapper.listByPage();
    }*/


    /**
     * 获取家人列表(分页）
     *
     * @return 家人列表
     */
    @Autowired
    private BedMapper bedMapper;

    @Autowired
    private RoomMapper  roomMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public List<MemberVo> listByPage() {
        List<MemberVo> memberVoList = new ArrayList<>();

        // 1.获取当前登录用户id
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("用户未登录");
        }

        // 2.根据用户id查询家人信息
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(
                new LambdaQueryWrapper<FamilyMemberElder>().eq(FamilyMemberElder::getFamilyMemberId, userId));
        if (ObjectUtil.isEmpty(familyMemberElders)) {
            // 没有家人，返回空列表
            return memberVoList;
        }

        familyMemberElders.forEach(fme -> {
            MemberVo memberVo = new MemberVo();
            memberVo.setMid(fme.getId().toString());
            memberVo.setMremark(fme.getRemark());
            memberVo.setElderId(fme.getElderId().toString());

            // 获取老人信息
            Elder elder = elderMapper.selectOne(new LambdaQueryWrapper<Elder>().eq(Elder::getId, fme.getElderId()));
            memberVo.setName(elder.getName());
            memberVo.setImage(elder.getImage());
            memberVo.setBedNumber(elder.getBedNumber());

            // 根据床号获取房间id,再根据房间id获取房间类型名称
            Long roomId = bedMapper.selectById(elder.getBedId()).getRoomId();
            memberVo.setTypeName(roomMapper.selectById(roomId).getTypeName());

            // 获取IoT设备信息
            Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(
                    Device::getBindingLocation,
                    elder.getId()
            ));
            memberVo.setIotId(device.getIotId());
            memberVo.setDeviceName(device.getDeviceName());
            memberVo.setProductKey(device.getProductKey());

            memberVoList.add(memberVo);
        });
        return memberVoList;
    }

    /**
     * 查询设备属性状态
     * @param devicePropertyStatusDto
     * @return
     */
    @Override
    public ListVo queryDevicePropertyStatus(DevicePropertyStatusDto devicePropertyStatusDto) {
        //1. 根据产品key从IOT平台查询产品服务的具体信息
        //2. 从前端参数中获取产品的key
        String product_id = devicePropertyStatusDto.getProductKey();
        //3. 查询IOT平台获取数据
        ShowProductResponse showProductResponse;
        try {
            showProductResponse = ioTDAClient.showProduct(new ShowProductRequest().withProductId(product_id));
        } catch (Exception e) {
            throw new BaseException("物联网接口 - 获取产品信息，调用失败");
        }
        //4. 将产品数据转换成实体类
        if (ObjectUtil.isEmpty(showProductResponse)) {
            log.warn("IOT平台数据为空");
            return null;
        }
        //4. 遍历showProductResponse，将其中的服务都拿出来
        List<ServiceCapability> serviceCapabilities = showProductResponse.getServiceCapabilities();
        if (CollUtil.isEmpty(serviceCapabilities)) {
            log.warn("IOT平台数据为空");
            return null;
        }
        //5. 根据产品key和设备iotId获取redis中最新的设备数据
        String key = devicePropertyStatusDto.getProductKey()  + "_" + devicePropertyStatusDto.getDeviceName();
        Object obj = redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_LAST_DATA, key);
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        String jsonStr = JSONUtil.toJsonStr(obj);
        List<DeviceData> deviceLastDatalist = JSONUtil.toList(jsonStr,DeviceData.class);
        //6. 遍历服务，将服务中的属性都拿出来
        // 标记开始时间
        long startTime = System.currentTimeMillis();
        PropertyListVo propertiesStatusInfo = new PropertyListVo();
        List<PropertyStatusInfo> propertyStatusInfoList = new ArrayList<>();
        serviceCapabilities.forEach(serviceCapability -> {
            serviceCapability.getProperties().forEach(property -> {
                PropertyStatusInfo propertyStatusInfo = new PropertyStatusInfo();
                propertyStatusInfo.setDataType(property.getDataType());
                String functionId = property.getPropertyName();
                propertyStatusInfo.setIdentifier(functionId);
                propertyStatusInfo.setName(property.getDescription());
                propertyStatusInfo.setUnit(property.getUnit());
                // 遍历deviceLastDatalist，获取到对应的值
                deviceLastDatalist.forEach(deviceLastData -> {
                    if (functionId.equals(deviceLastData.getFunctionId())) {
                        propertyStatusInfo.setValue(deviceLastData.getDataValue());
                        propertyStatusInfo.setTime(deviceLastData.getAlarmTime());
                    }
                });
                propertyStatusInfoList.add(propertyStatusInfo);
            });
        });
        // 标记结束时间
        long  endTime = System.currentTimeMillis();
        log.info("查询设备属性状态耗时：{}ms", endTime - startTime);

        propertiesStatusInfo.setPropertyStatusInfo(propertyStatusInfoList);
        ListVo list = new ListVo();
        list.setList(propertiesStatusInfo);
        return list;
    }
}
